package db

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"navidog/config"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/pingcap/tidb/pkg/parser/ast"
)

// ColumnInfo 存储列的详细信息
type ColumnInfo struct {
	Name            string
	IsAutoIncrement bool
}

type DB struct {
	*sqlx.DB
	mu              sync.Mutex
	readOnlyMode    bool
	processingFiles map[string]bool                     // 跟踪正在处理的文件
	jsonCache       map[string][]map[string]interface{} // 缓存JSON文件的原始结果
	logDir          string                              // 日志目录
	logPrefix       string                              // 日志文件名前缀
	sshTunnel       *SSHTunnel                          // SSH隧道
}

// globalLogDir holds the directory used for SQL execution logs. It can be set
// once from the main package via SetGlobalLogDir and will be copied into each
// DB instance upon creation so that each instance keeps its own value even if
// the global is changed later.
var globalLogDir string

// SetGlobalLogDir sets the default directory where SQL execution logs will be
// stored. It is safe to call this multiple times; every subsequent DB or
// BigQueryDB constructed will capture the latest value.
func SetGlobalLogDir(dir string) {
	globalLogDir = dir
}

// SetLogPrefix sets per-instance prefix for log file names.
func (d *DB) SetLogPrefix(prefix string) {
	d.logPrefix = prefix
}

func New(dsn string) (*DB, error) {
	db, err := sqlx.Connect("mysql", dsn)
	if err != nil {
		return nil, fmt.Errorf("could not connect to database: %w", err)
	}

	// 配置连接池参数以防止连接断线
	// 设置连接最大生命周期，避免长时间连接被服务器关闭
	db.SetConnMaxLifetime(time.Hour)
	// 设置连接最大空闲时间
	db.SetConnMaxIdleTime(time.Hour)
	// 设置最大打开连接数
	db.SetMaxOpenConns(25)
	// 设置最大空闲连接数，与最大打开连接数相同以避免频繁开关连接
	db.SetMaxIdleConns(25)

	// 测试连接是否可用
	if err := db.Ping(); err != nil {
		db.Close()
		return nil, fmt.Errorf("could not ping database: %w", err)
	}

	return &DB{
		DB:              db,
		readOnlyMode:    false,
		processingFiles: make(map[string]bool),
		jsonCache:       make(map[string][]map[string]interface{}),
		logDir:          globalLogDir,
		logPrefix:       "mysql",
	}, nil
}

func NewWithReadOnly(dsn string, readOnlyMode bool) (*DB, error) {
	db, err := sqlx.Connect("mysql", dsn)
	if err != nil {
		return nil, fmt.Errorf("could not connect to database: %w", err)
	}

	// 配置连接池参数以防止连接断线
	// 设置连接最大生命周期，避免长时间连接被服务器关闭
	db.SetConnMaxLifetime(time.Hour)
	// 设置连接最大空闲时间
	db.SetConnMaxIdleTime(time.Hour)
	// 设置最大打开连接数
	db.SetMaxOpenConns(25)
	// 设置最大空闲连接数，与最大打开连接数相同以避免频繁开关连接
	db.SetMaxIdleConns(25)

	// 测试连接是否可用
	if err := db.Ping(); err != nil {
		db.Close()
		return nil, fmt.Errorf("could not ping database: %w", err)
	}

	return &DB{
		DB:              db,
		readOnlyMode:    readOnlyMode,
		processingFiles: make(map[string]bool),
		jsonCache:       make(map[string][]map[string]interface{}),
		logDir:          globalLogDir,
		logPrefix:       "mysql",
	}, nil
}

// NewWithSSH 使用SSH隧道创建MySQL连接
func NewWithSSH(sshConfig config.SSHConfig, mysqlHost string, mysqlPort int, mysqlUser, mysqlPassword, mysqlDatabase string, readOnlyMode bool) (*DB, error) {
	// 设置SSH隧道配置的默认值
	if sshConfig.Port == 0 {
		sshConfig.Port = 22
	}
	if !sshConfig.KeepAlive {
		sshConfig.KeepAlive = true
	}
	if !sshConfig.TCPNoDelay {
		sshConfig.TCPNoDelay = true
	}

	// 创建SSH隧道
	tunnelConfig := SSHTunnelConfig{
		SSHHost:        sshConfig.Host,
		SSHPort:        sshConfig.Port,
		SSHUser:        sshConfig.User,
		SSHPassword:    sshConfig.Password,
		SSHPrivateKey:  sshConfig.PrivateKey,
		SSHPassphrase:  sshConfig.Passphrase,
		LocalPort:      sshConfig.LocalPort,
		RemoteHost:     mysqlHost,
		RemotePort:     mysqlPort,
		KeepAlive:      sshConfig.KeepAlive,
		TCPNoDelay:     sshConfig.TCPNoDelay,
		SendBufferSize: sshConfig.SendBufferSize,
		RecvBufferSize: sshConfig.RecvBufferSize,
	}

	tunnel, err := NewSSHTunnel(tunnelConfig)
	if err != nil {
		return nil, fmt.Errorf("创建SSH隧道失败: %w", err)
	}

	// 启动SSH隧道
	if err := tunnel.Start(); err != nil {
		tunnel.Close()
		return nil, fmt.Errorf("启动SSH隧道失败: %w", err)
	}

	// 解析本地地址获取端口
	_, localPortStr, err := net.SplitHostPort(tunnel.GetLocalAddr())
	if err != nil {
		tunnel.Close()
		return nil, fmt.Errorf("解析SSH隧道本地地址失败: %w", err)
	}

	// 构建通过SSH隧道的DSN
	dsn := fmt.Sprintf("%s:%s@tcp(127.0.0.1:%s)/%s?parseTime=true",
		mysqlUser, mysqlPassword, localPortStr, mysqlDatabase)

	// 创建数据库连接
	db, err := sqlx.Connect("mysql", dsn)
	if err != nil {
		tunnel.Close()
		return nil, fmt.Errorf("通过SSH隧道连接MySQL失败: %w", err)
	}

	// 配置连接池参数，针对SSH连接进行优化
	db.SetConnMaxLifetime(2 * time.Hour)    // SSH连接更稳定，可以设置更长的生命周期
	db.SetConnMaxIdleTime(30 * time.Minute) // 较短的空闲时间以避免隧道超时
	db.SetMaxOpenConns(10)                  // SSH隧道限制并发连接数
	db.SetMaxIdleConns(5)                   // 保持少量空闲连接

	// 测试连接是否可用
	if err := db.Ping(); err != nil {
		db.Close()
		tunnel.Close()
		return nil, fmt.Errorf("通过SSH隧道ping MySQL失败: %w", err)
	}

	log.Printf("成功通过SSH隧道连接到MySQL: %s@%s:%d -> 127.0.0.1:%s -> %s:%d",
		sshConfig.User, sshConfig.Host, sshConfig.Port, localPortStr, mysqlHost, mysqlPort)

	return &DB{
		DB:              db,
		readOnlyMode:    readOnlyMode,
		processingFiles: make(map[string]bool),
		jsonCache:       make(map[string][]map[string]interface{}),
		logDir:          globalLogDir,
		logPrefix:       "mysql-ssh",
		sshTunnel:       tunnel,
	}, nil
}

func (d *DB) Close() error {
	if d.sshTunnel != nil {
		d.sshTunnel.Close()
	}
	return d.DB.Close()
}

func (d *DB) IsReadOnlyQuery(query string) bool {
	return IsReadOnlyQuery(query)
}

// executeWithRetry 带重试机制的查询执行，处理连接断线的情况
func (d *DB) executeWithRetry(query string, isReadOnly bool, maxRetries int) (interface{}, error) {
	var lastErr error

	for attempt := 0; attempt <= maxRetries; attempt++ {
		if attempt > 0 {
			// 重试前等待一下，避免立即重试
			time.Sleep(time.Duration(attempt) * 100 * time.Millisecond)
		}

		if isReadOnly {
			rows, err := d.Queryx(query)
			if err != nil {
				lastErr = err
				// 检查是否是连接相关的错误
				if isConnectionError(err) && attempt < maxRetries {
					continue // 重试
				}
				return nil, fmt.Errorf("query error: %w", err)
			}
			defer rows.Close()

			results := []map[string]interface{}{}
			for rows.Next() {
				result := make(map[string]interface{})
				if err := rows.MapScan(result); err != nil {
					return nil, fmt.Errorf("scan error: %w", err)
				}
				// 将 []byte 转换为 string
				for k, v := range result {
					if b, ok := v.([]byte); ok {
						result[k] = string(b)
					}
				}
				results = append(results, result)
			}
			return results, nil
		} else {
			// 处理非查询语句
			result, err := d.Exec(query)
			if err != nil {
				lastErr = err
				// 检查是否是连接相关的错误
				if isConnectionError(err) && attempt < maxRetries {
					continue // 重试
				}
				return nil, fmt.Errorf("exec error: %w", err)
			}

			rowsAffected, _ := result.RowsAffected()
			return map[string]interface{}{
				"rows_affected": rowsAffected,
				"status":        "success",
				"description":   "Write operation completed",
			}, nil
		}
	}

	return nil, lastErr
}

// isConnectionError 检查是否是连接相关的错误
func isConnectionError(err error) bool {
	if err == nil {
		return false
	}
	errStr := strings.ToLower(err.Error())
	connectionErrors := []string{
		"connection refused",
		"connection reset",
		"connection lost",
		"broken pipe",
		"bad connection",
		"invalid connection",
		"server has gone away",
		"eof",
		"timeout",
		"connection closed",
	}

	for _, connErr := range connectionErrors {
		if strings.Contains(errStr, connErr) {
			return true
		}
	}
	return false
}

// splitSQLStatements 分割多条SQL语句
func splitSQLStatements(sqlContent string) []string {
	// 简单的SQL语句分割逻辑
	// 按分号分割，但要考虑字符串中的分号
	var statements []string
	var current strings.Builder
	inQuotes := false
	inDoubleQuotes := false
	escaped := false

	for _, char := range sqlContent {
		switch char {
		case '\\':
			escaped = !escaped
			current.WriteRune(char)
		case '\'':
			if !escaped && !inDoubleQuotes {
				inQuotes = !inQuotes
			}
			escaped = false
			current.WriteRune(char)
		case '"':
			if !escaped && !inQuotes {
				inDoubleQuotes = !inDoubleQuotes
			}
			escaped = false
			current.WriteRune(char)
		case ';':
			escaped = false
			if !inQuotes && !inDoubleQuotes {
				// 分号在字符串外，这是一个语句结束
				stmt := strings.TrimSpace(current.String())
				if stmt != "" {
					statements = append(statements, stmt)
				}
				current.Reset()
			} else {
				current.WriteRune(char)
			}
		default:
			escaped = false
			current.WriteRune(char)
		}
	}

	// 处理最后一个语句（可能没有分号结尾）
	stmt := strings.TrimSpace(current.String())
	if stmt != "" {
		statements = append(statements, stmt)
	}

	return statements
}

// ExecuteMultipleQueries 执行多条SQL语句
func (d *DB) ExecuteMultipleQueries(sqlContent string) ([]map[string]interface{}, error) {
	statements := splitSQLStatements(sqlContent)
	if len(statements) == 0 {
		return nil, fmt.Errorf("no valid SQL statements found")
	}

	var results []map[string]interface{}

	for i, stmt := range statements {
		// 检查当前语句是否是只读查询
		isReadOnly := d.IsReadOnlyQuery(stmt)

		// 如果在只读模式下且不是只读查询，则跳过该语句
		if d.readOnlyMode && !isReadOnly {
			errorResult := map[string]interface{}{
				"statement_index": i + 1,
				"statement":       stmt,
				"error":           "write operations are not allowed in read-only mode",
			}
			results = append(results, errorResult)
			continue
		}

		// 直接调用executeWithRetry避免递归
		result, err := d.executeWithRetry(stmt, isReadOnly, 3)
		if err != nil {
			// 返回错误信息，包括语句序号
			errorResult := map[string]interface{}{
				"statement_index": i + 1,
				"statement":       stmt,
				"error":           err.Error(),
			}
			results = append(results, errorResult)
			// 继续执行剩余的语句，而不是立即返回错误
		} else {
			// 成功执行的结果
			successResult := map[string]interface{}{
				"statement_index": i + 1,
				"statement":       stmt,
				"result":          result,
			}
			results = append(results, successResult)
		}
	}

	return results, nil
}

func (d *DB) ExecuteQuery(query string) (interface{}, error) {
	// 检查是否包含多条语句
	statements := splitSQLStatements(query)
	if len(statements) > 1 {
		// 如果有多条语句，使用ExecuteMultipleQueries
		return d.ExecuteMultipleQueries(query)
	}

	// 单条语句的处理逻辑
	// 检查是否是只读查询
	isReadOnly := d.IsReadOnlyQuery(query)

	// 如果在只读模式下且不是只读查询，则拒绝执行
	if d.readOnlyMode && !isReadOnly {
		return nil, fmt.Errorf("write operations are not allowed in read-only mode")
	}

	// 使用带重试机制的执行方法
	return d.executeWithRetry(query, isReadOnly, 3)
}

func (d *DB) ProcessSQLFile(sqlPath string) error {
	content, err := os.ReadFile(sqlPath)
	if err != nil {
		return fmt.Errorf("could not read SQL file: %w", err)
	}

	// 读取文件内容并去除首尾空白
	sqlContent := strings.TrimSpace(string(content))
	if sqlContent == "" {
		// 空文件，直接返回
		return nil
	}

	// 检查最后一行是否是 GO
	lines := strings.Split(sqlContent, "\n")
	lastLine := strings.TrimSpace(lines[len(lines)-1])

	// 如果是非只读查询且最后一行不是 GO，则跳过
	isReadOnly := d.IsReadOnlyQuery(sqlContent)
	if !isReadOnly && lastLine != "GO" {
		return nil
	}

	// 如果在只读模式下且不是只读查询，则拒绝执行
	if d.readOnlyMode && !isReadOnly {
		return fmt.Errorf("write operations are not allowed in read-only mode")
	}

	// 如果是 GO 命令，则删除该行并更新文件
	if lastLine == "GO" {
		sqlContent = strings.Join(lines[:len(lines)-1], "\n")
		if err := os.WriteFile(sqlPath, []byte(sqlContent), 0644); err != nil {
			return fmt.Errorf("could not update SQL file: %w", err)
		}
	}

	// 执行查询
	var queryResult interface{}
	queryResult, err = d.ExecuteQuery(sqlContent)
	if err != nil {
		queryResult = map[string]string{"error": err.Error()}
	}

	// 标准化查询结果中的时间格式
	queryResult = d.normalizeTimeInResult(queryResult)

	// Marshal output JSON for embedding in markdown
	jsonData, err := json.MarshalIndent(queryResult, "", "  ")
	if err != nil {
		return fmt.Errorf("could not marshal results: %w", err)
	}

	// --- 安全地确定输出文件名 ---
	d.mu.Lock()
	defer d.mu.Unlock()

	basePath := strings.TrimSuffix(sqlPath, filepath.Ext(sqlPath))
	mdPath := basePath + ".md"

	// 标记结果文件正在被SQL处理更新，避免触发UPDATE生成
	d.processingFiles[mdPath] = true
	defer func() {
		// 延迟一段时间后移除标记，给文件系统时间处理
		go func() {
			time.Sleep(100 * time.Millisecond)
			d.mu.Lock()
			delete(d.processingFiles, mdPath)
			d.mu.Unlock()
		}()
	}()

	// 缓存查询结果到内存，用于后续的diff对比
	if resultSlice, ok := queryResult.([]map[string]interface{}); ok {
		d.jsonCache[mdPath] = resultSlice
	}

	// 生成markdown内容
	mdContent := fmt.Sprintf("## SQL\n```sql\n%s\n```\n\n## Result\n```json\n%s\n```\n", sqlContent, string(jsonData))

	if err := os.WriteFile(mdPath, []byte(mdContent), 0644); err != nil {
		return fmt.Errorf("could not write result markdown file: %w", err)
	}

	// 写入查询日志
	d.writeQueryLog(sqlContent, queryResult)

	// 如果是query.sql文件且不存在insert.sql，则自动创建一个
	if filepath.Base(sqlPath) == "query.sql" {
		d.autoCreateInsertSQL(sqlPath, queryResult)
	}

	return nil
}

// ProcessJSONModification 处理JSON文件修改，生成UPDATE语句
func (d *DB) ProcessJSONModification(resultPath string) error {
	// 如果在只读模式下，跳过UPDATE语句生成
	if d.readOnlyMode {
		return nil
	}

	// 检查文件是否正在被SQL处理（避免query.sql触发的结果文件更新生成UPDATE）
	d.mu.Lock()
	isProcessing := d.processingFiles[resultPath]
	cachedResult, hasCached := d.jsonCache[resultPath]
	d.mu.Unlock()

	if isProcessing {
		return nil // 跳过SQL触发的JSON更新
	}

	if !hasCached {
		return nil // 没有缓存的原始结果，无法进行对比
	}

	// 读取当前JSON文件内容
	content, err := os.ReadFile(resultPath)
	if err != nil {
		return fmt.Errorf("could not read JSON file: %w", err)
	}

	var currentResult QueryResult
	if filepath.Ext(resultPath) == ".json" {
		if err := json.Unmarshal(content, &currentResult); err != nil {
			return fmt.Errorf("could not parse JSON file: %w", err)
		}
	} else {
		// markdown: extract json block
		strContent := string(content)
		startIdx := strings.Index(strContent, "```json")
		if startIdx == -1 {
			return nil // 没有json代码块
		}
		startIdx += len("```json")
		endIdx := strings.Index(strContent[startIdx:], "```")
		if endIdx == -1 {
			return nil // 缺少结束标记
		}
		jsonText := strings.TrimSpace(strContent[startIdx : startIdx+endIdx])

		var parsed interface{}
		if err := json.Unmarshal([]byte(jsonText), &parsed); err != nil {
			return fmt.Errorf("could not parse JSON block: %w", err)
		}

		currentResult.Result = parsed
	}

	// 确保结果是切片格式
	resultSlice, ok := currentResult.Result.([]interface{})
	if !ok {
		// 如果不是查询结果（比如是错误信息），则跳过
		return nil
	}

	if len(resultSlice) == 0 {
		return nil
	}

	// 从文件路径推断表名
	tableName := filepath.Base(filepath.Dir(resultPath))

	// 获取表的主键或唯一键
	keyColumns, err := d.GetTablePrimaryKey(tableName)
	if err != nil {
		return fmt.Errorf("could not get primary key for table %s: %w", tableName, err)
	}

	if len(keyColumns) == 0 {
		return fmt.Errorf("table %s has no primary key or unique key, cannot generate UPDATE statements", tableName)
	}

	// 使用内存中缓存的原始结果与当前修改后的结果进行精准对比
	updateStatements, err := d.generateUpdateStatementsFromCache(tableName, keyColumns, cachedResult, resultSlice)
	if err != nil {
		return fmt.Errorf("could not generate update statements: %w", err)
	}

	if len(updateStatements) == 0 {
		return nil // 没有变更
	}

	// 将UPDATE语句追加到update.sql文件
	updateFilePath := filepath.Join(filepath.Dir(resultPath), "update.sql")

	// 准备写入的内容
	updateContent := fmt.Sprintf("-- Generated at %s for table %s\n",
		time.Now().Format("2006-01-02 15:04:05"), tableName)
	for _, stmt := range updateStatements {
		updateContent += stmt + ";\n"
	}
	updateContent += "\n"

	// 追加到文件
	f, err := os.OpenFile(updateFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return fmt.Errorf("could not open update.sql file: %w", err)
	}
	defer f.Close()

	if _, err := f.WriteString(updateContent); err != nil {
		return fmt.Errorf("could not write to update.sql file: %w", err)
	}

	// 更新缓存为当前修改后的结果
	d.mu.Lock()
	if modifiedSlice := d.convertToMapSlice(resultSlice); modifiedSlice != nil {
		d.jsonCache[resultPath] = modifiedSlice
	}
	d.mu.Unlock()

	return nil
}

// ProcessInsertSQL 处理insert.sql文件，将JSON内容转换为INSERT语句
func (d *DB) ProcessInsertSQL(insertPath string) error {
	// 如果在只读模式下，跳过INSERT语句生成
	if d.readOnlyMode {
		return nil
	}

	// 读取insert.sql文件内容
	content, err := os.ReadFile(insertPath)
	if err != nil {
		return fmt.Errorf("could not read insert.sql file: %w", err)
	}

	// 去除首尾空白
	sqlContent := strings.TrimSpace(string(content))
	sqlContent = strings.Trim(sqlContent, ",")
	sqlContent = strings.TrimSpace(sqlContent)
	if sqlContent == "" {
		return nil // 空文件，直接返回
	}

	// 检查内容是否是JSON格式
	var jsonData []map[string]interface{}
	if err := json.Unmarshal([]byte(sqlContent), &jsonData); err != nil {
		// 尝试修复常见的JSON格式问题
		fixedJSON := d.fixJSONFormat(sqlContent)
		if err := json.Unmarshal([]byte(fixedJSON), &jsonData); err != nil {
			// 仍然不是JSON格式，按普通SQL文件处理
			return d.ProcessSQLFile(insertPath)
		}
	}

	if len(jsonData) == 0 {
		return nil // 空JSON数组，直接返回
	}

	// 从文件路径推断表名
	dir := filepath.Dir(insertPath)
	tableName := filepath.Base(dir)

	// 检查同目录下是否存在ddl.sql文件
	ddlPath := filepath.Join(dir, "ddl.sql")
	if _, err := os.Stat(ddlPath); os.IsNotExist(err) {
		return fmt.Errorf("ddl.sql file not found in directory %s, cannot generate INSERT statements", dir)
	}

	// 读取DDL文件获取表结构
	ddlContent, err := os.ReadFile(ddlPath)
	if err != nil {
		return fmt.Errorf("could not read ddl.sql file: %w", err)
	}

	// 解析DDL获取列信息
	columns, err := d.parseColumnsFromDDL(string(ddlContent))
	if err != nil {
		return fmt.Errorf("could not parse columns from DDL: %w", err)
	}

	// 生成INSERT语句
	insertStatements, err := d.generateInsertStatements(tableName, columns, jsonData)
	if err != nil {
		return fmt.Errorf("could not generate INSERT statements: %w", err)
	}

	if len(insertStatements) == 0 {
		return nil // 没有要插入的数据
	}

	// 将生成的INSERT语句写回insert.sql文件
	insertContent := fmt.Sprintf("-- Generated INSERT statements for table %s at %s\n",
		tableName, time.Now().Format("2006-01-02 15:04:05"))
	insertContent += strings.Join(insertStatements, ";\n") + ";\n"

	if err := os.WriteFile(insertPath, []byte(insertContent), 0644); err != nil {
		return fmt.Errorf("could not write INSERT statements to file: %w", err)
	}

	log.Printf("Successfully generated %d INSERT statements for table %s", len(insertStatements), tableName)
	return nil
}

// parseColumnsFromDDL 从DDL语句中解析列信息
func (d *DB) parseColumnsFromDDL(ddlSQL string) ([]ColumnInfo, error) {
	// 使用TiDB parser解析DDL
	localStmt, err := parseDDL(ddlSQL)
	if err != nil {
		return nil, fmt.Errorf("failed to parse DDL: %w", err)
	}

	var columns []ColumnInfo
	for _, col := range localStmt.Cols {
		if col.Name != nil {
			colInfo := ColumnInfo{
				Name:            col.Name.Name.L,
				IsAutoIncrement: false,
			}

			// 检查是否是自增列
			for _, option := range col.Options {
				if option.Tp == ast.ColumnOptionAutoIncrement {
					colInfo.IsAutoIncrement = true
					break
				}
			}

			columns = append(columns, colInfo)
		}
	}

	return columns, nil
}

// generateInsertStatements 生成INSERT语句
func (d *DB) generateInsertStatements(tableName string, columns []ColumnInfo, jsonData []map[string]interface{}) ([]string, error) {
	var statements []string

	for _, row := range jsonData {
		// 构建INSERT语句
		var columnNames []string
		var values []string

		// 按DDL中的列顺序处理
		for _, col := range columns {
			// 跳过自增列
			if col.IsAutoIncrement {
				continue
			}

			if val, exists := row[col.Name]; exists {
				columnNames = append(columnNames, fmt.Sprintf("`%s`", col.Name))
				values = append(values, d.formatValue(val))
			}
		}

		if len(columnNames) > 0 {
			stmt := fmt.Sprintf("INSERT INTO `%s` (%s) VALUES (%s)",
				tableName,
				strings.Join(columnNames, ", "),
				strings.Join(values, ", "))
			statements = append(statements, stmt)
		}
	}

	return statements, nil
}

// generateUpdateStatementsFromCache 使用缓存数据生成UPDATE语句
func (d *DB) generateUpdateStatementsFromCache(tableName string, keyColumns []string, original []map[string]interface{}, modified []interface{}) ([]string, error) {
	var updateStatements []string

	// 将original转换为按主键索引的map
	originalMap := make(map[string]map[string]interface{})
	for _, row := range original {
		key := d.buildKeyString(keyColumns, row)
		originalMap[key] = row
	}

	// 处理modified数据
	for _, modItem := range modified {
		modRow, ok := modItem.(map[string]interface{})
		if !ok {
			continue
		}

		key := d.buildKeyString(keyColumns, modRow)
		originalRow, exists := originalMap[key]

		if !exists {
			continue // 原始数据中不存在，跳过
		}

		// 比较并生成UPDATE语句
		updateStmt := d.buildUpdateStatement(tableName, keyColumns, originalRow, modRow)
		if updateStmt != "" {
			updateStatements = append(updateStatements, updateStmt)
			// 调试日志：记录生成的UPDATE语句
		}
	}

	return updateStatements, nil
}

// convertToMapSlice 将[]interface{}转换为[]map[string]interface{}
func (d *DB) convertToMapSlice(data []interface{}) []map[string]interface{} {
	var result []map[string]interface{}
	for _, item := range data {
		if mapItem, ok := item.(map[string]interface{}); ok {
			result = append(result, mapItem)
		}
	}
	if len(result) == 0 {
		return nil
	}
	return result
}

// generateUpdateStatements 生成UPDATE语句
func (d *DB) generateUpdateStatements(tableName string, keyColumns []string, original []map[string]interface{}, modified []interface{}) ([]string, error) {
	var updateStatements []string

	// 将original转换为按主键索引的map
	originalMap := make(map[string]map[string]interface{})
	for _, row := range original {
		key := d.buildKeyString(keyColumns, row)
		originalMap[key] = row
	}

	// 处理modified数据
	for _, modItem := range modified {
		modRow, ok := modItem.(map[string]interface{})
		if !ok {
			continue
		}

		key := d.buildKeyString(keyColumns, modRow)
		originalRow, exists := originalMap[key]

		if !exists {
			continue // 原始数据中不存在，跳过
		}

		// 比较并生成UPDATE语句
		updateStmt := d.buildUpdateStatement(tableName, keyColumns, originalRow, modRow)
		if updateStmt != "" {
			updateStatements = append(updateStatements, updateStmt)
		}
	}

	return updateStatements, nil
}

// buildKeyString 构建主键字符串用于索引
func (d *DB) buildKeyString(keyColumns []string, row map[string]interface{}) string {
	var keyParts []string
	for _, col := range keyColumns {
		val := fmt.Sprintf("%v", row[col])
		keyParts = append(keyParts, val)
	}
	return strings.Join(keyParts, "|")
}

// buildUpdateStatement 构建单个UPDATE语句
func (d *DB) buildUpdateStatement(tableName string, keyColumns []string, original, modified map[string]interface{}) string {
	var setParts []string
	var whereParts []string

	// 构建WHERE子句
	for _, col := range keyColumns {
		val := original[col]
		whereParts = append(whereParts, fmt.Sprintf("`%s` = %s", col, d.formatValue(val)))
	}

	// 比较字段并构建SET子句
	for col, modVal := range modified {
		// 跳过主键列
		isKeyColumn := false
		for _, keyCol := range keyColumns {
			if col == keyCol {
				isKeyColumn = true
				break
			}
		}
		if isKeyColumn {
			continue
		}

		origVal, exists := original[col]
		if !exists {
			continue
		}

		// 标准化后比较
		// origNorm := d.normalizeValue(origVal)
		// modNorm := d.normalizeValue(modVal)
		equal := d.valuesEqual(origVal, modVal)

		// 详细调试日志

		// 比较值是否不同
		if !equal {
			setParts = append(setParts, fmt.Sprintf("`%s` = %s", col, d.formatValue(modVal)))
		}
	}

	// 如果没有要更新的字段，返回空字符串
	if len(setParts) == 0 {
		return ""
	}

	return fmt.Sprintf("UPDATE `%s` SET %s WHERE %s",
		tableName,
		strings.Join(setParts, ", "),
		strings.Join(whereParts, " AND "))
}

// formatValue 格式化值用于SQL语句
func (d *DB) formatValue(val interface{}) string {
	if val == nil {
		return "NULL"
	}

	switch v := val.(type) {
	case string:
		// 转义单引号
		escaped := strings.ReplaceAll(v, "'", "''")
		return fmt.Sprintf("'%s'", escaped)
	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
		return fmt.Sprintf("%v", v)
	case float32, float64:
		return fmt.Sprintf("%v", v)
	case bool:
		if v {
			return "1"
		}
		return "0"
	default:
		// 对于其他类型，转换为字符串并添加引号
		escaped := strings.ReplaceAll(fmt.Sprintf("%v", v), "'", "''")
		return fmt.Sprintf("'%s'", escaped)
	}
}

// valuesEqual 比较两个值是否相等
func (d *DB) valuesEqual(a, b interface{}) bool {
	// 处理nil值
	if a == nil && b == nil {
		return true
	}
	if a == nil || b == nil {
		return false
	}

	// 特殊处理时间类型
	aStr := d.normalizeValue(a)
	bStr := d.normalizeValue(b)

	return aStr == bStr
}

// normalizeValue 标准化值用于比较
func (d *DB) normalizeValue(val interface{}) string {
	if val == nil {
		return "NULL"
	}

	switch v := val.(type) {
	case time.Time:
		// 专门处理time.Time类型，统一格式为 "2006-01-02 15:04:05"
		return v.Format("2006-01-02 15:04:05")
	case string:
		// 处理时间字符串，统一格式
		if d.isTimeString(v) {
			return d.normalizeTimeString(v)
		}
		return v
	case []byte:
		// MySQL有时返回[]byte，转换为string
		str := string(v)
		if d.isTimeString(str) {
			return d.normalizeTimeString(str)
		}
		return str
	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
		return fmt.Sprintf("%d", v)
	case float32, float64:
		return fmt.Sprintf("%.10g", v) // 使用固定精度避免浮点数差异
	case bool:
		if v {
			return "true"
		}
		return "false"
	default:
		// 对于其他类型，先转换为字符串，然后检查是否是时间格式
		str := fmt.Sprintf("%v", v)
		if d.isTimeString(str) {
			return d.normalizeTimeString(str)
		}
		return str
	}
}

// isTimeString 检查字符串是否是时间格式
func (d *DB) isTimeString(s string) bool {
	// 更精确的时间格式检测
	if len(s) < 10 {
		return false
	}

	// 检查是否包含日期格式 YYYY-MM-DD
	if len(s) >= 10 && s[4] == '-' && s[7] == '-' {
		// 检查年月日是否都是数字
		if d.isDigit(s[0]) && d.isDigit(s[1]) && d.isDigit(s[2]) && d.isDigit(s[3]) &&
			d.isDigit(s[5]) && d.isDigit(s[6]) && d.isDigit(s[8]) && d.isDigit(s[9]) {
			return true
		}
	}

	// 检查是否包含UTC时区信息 (MySQL Go驱动返回的格式)
	if strings.Contains(s, " UTC") || strings.Contains(s, "+0000") {
		return true
	}

	return false
}

// isDigit 检查字符是否是数字
func (d *DB) isDigit(c byte) bool {
	return c >= '0' && c <= '9'
}

// normalizeTimeString 标准化时间字符串
func (d *DB) normalizeTimeString(s string) string {
	// 处理MySQL Go驱动返回的格式: "2020-07-22 00:00:00 +0000 UTC"
	if strings.Contains(s, " UTC") {
		// 移除 " +0000 UTC" 或类似的时区信息
		if idx := strings.Index(s, " +"); idx != -1 {
			s = s[:idx]
		} else if idx := strings.Index(s, " UTC"); idx != -1 {
			s = s[:idx]
		}
	}

	// 移除末尾的Z
	if strings.HasSuffix(s, "Z") {
		s = s[:len(s)-1]
	}

	// 移除毫秒部分
	if idx := strings.Index(s, "."); idx != -1 {
		s = s[:idx]
	}

	// 统一T分隔符为空格（使用MySQL标准格式: "2006-01-02 15:04:05"）
	s = strings.ReplaceAll(s, "T", " ")

	return s
}

// writeQueryLog writes the SQL and its result into a markdown-formatted log
// file inside the configured logDir. The directory structure is
// {logDir}/YYYY-MM-DD/HH-MM-SS.md. If logDir is empty, the call is a no-op.
func (d *DB) writeQueryLog(sqlContent string, queryResult interface{}) {
	if d.logDir == "" {
		return
	}

	// Create date-based directory
	now := time.Now()
	dateDir := filepath.Join(d.logDir, now.Format("2006-01-02"))
	if err := os.MkdirAll(dateDir, 0755); err != nil {
		return // silently ignore logging errors
	}

	prefix := d.logPrefix
	if prefix == "" {
		prefix = "mysql"
	}

	filePath := filepath.Join(dateDir, fmt.Sprintf("%s_%s.md", prefix, now.Format("15_04_05")))

	jsonBytes, err := json.MarshalIndent(queryResult, "", "  ")
	if err != nil {
		// Fallback to plain fmt if marshal fails
		jsonBytes = []byte(fmt.Sprintf("%v", queryResult))
	}

	content := fmt.Sprintf("## SQL\n```sql\n%s\n```\n\n## Result\n```json\n%s\n```\n", sqlContent, string(jsonBytes))

	_ = os.WriteFile(filePath, []byte(content), 0644)
}

// normalizeTimeInResult 标准化查询结果中的时间格式
func (d *DB) normalizeTimeInResult(result interface{}) interface{} {
	switch v := result.(type) {
	case []map[string]interface{}:
		// 处理查询结果数组
		for i, row := range v {
			for key, val := range row {
				v[i][key] = d.normalizeTimeValue(val)
			}
		}
		return v
	case map[string]interface{}:
		// 处理单个结果对象
		for key, val := range v {
			v[key] = d.normalizeTimeValue(val)
		}
		return v
	case []interface{}:
		// 处理接口数组
		for i, item := range v {
			v[i] = d.normalizeTimeInResult(item)
		}
		return v
	default:
		return result
	}
}

// normalizeTimeValue 标准化单个值中的时间格式
func (d *DB) normalizeTimeValue(val interface{}) interface{} {
	switch v := val.(type) {
	case time.Time:
		// 转换time.Time为标准格式字符串
		return v.Format("2006-01-02 15:04:05")
	case string:
		// 处理时间字符串
		if d.isTimeString(v) {
			return d.normalizeTimeString(v)
		}
		return v
	case []byte:
		// MySQL有时返回[]byte
		str := string(v)
		if d.isTimeString(str) {
			return d.normalizeTimeString(str)
		}
		return str
	default:
		return val
	}
}

// autoCreateInsertSQL 自动创建insert.sql文件（如果不存在）
func (d *DB) autoCreateInsertSQL(queryPath string, queryResult interface{}) {
	dir := filepath.Dir(queryPath)
	insertPath := filepath.Join(dir, "insert.sql")

	// 检查insert.sql是否已存在
	if _, err := os.Stat(insertPath); err == nil {
		return // 文件已存在，不覆盖
	}

	// 只对成功的查询结果生成insert.sql模板
	resultSlice, ok := queryResult.([]map[string]interface{})
	if !ok || len(resultSlice) == 0 {
		return // 不是查询结果或结果为空
	}

	// 尝试获取DDL信息来识别自增列
	ddlPath := filepath.Join(dir, "ddl.sql")
	var autoIncrementCols map[string]bool
	if ddlContent, err := os.ReadFile(ddlPath); err == nil {
		if columns, err := d.parseColumnsFromDDL(string(ddlContent)); err == nil {
			autoIncrementCols = make(map[string]bool)
			for _, col := range columns {
				if col.IsAutoIncrement {
					autoIncrementCols[col.Name] = true
				}
			}
		}
	}

	// 获取第一行数据作为模板，创建空的JSON数组结构
	firstRow := resultSlice[0]
	templateRow := make(map[string]interface{})

	// 为每个字段创建空值或示例值，但跳过自增列
	for key, val := range firstRow {
		// 跳过自增列
		if autoIncrementCols != nil && autoIncrementCols[key] {
			continue
		}

		switch val.(type) {
		case string:
			templateRow[key] = ""
		case int, int32, int64, float32, float64:
			templateRow[key] = 0
		case bool:
			templateRow[key] = false
		case nil:
			templateRow[key] = nil
		default:
			templateRow[key] = ""
		}
	}

	// 创建包含一个模板行的JSON数组
	templateData := []map[string]interface{}{templateRow}

	// 序列化为JSON
	jsonData, err := json.MarshalIndent(templateData, "", "  ")
	if err != nil {
		return // 序列化失败，跳过
	}

	// 写入insert.sql文件
	if err := os.WriteFile(insertPath, jsonData, 0644); err == nil {
		log.Printf("Auto-created insert.sql template for table %s", filepath.Base(dir))
	}
}

// fixJSONFormat 修复常见的JSON格式问题
func (d *DB) fixJSONFormat(content string) string {
	// 去除首尾空白
	content = strings.TrimSpace(content)

	// 处理单个对象的情况，如果不是数组格式，包装成数组
	if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") {
		// 检查是否是单个对象，如果是则包装成数组
		if !strings.HasPrefix(content, "[") {
			content = "[" + content + "]"
		}
	}

	// 处理多个对象用逗号分隔但没有数组包装的情况：{},{},{}
	if strings.Contains(content, "},{") && !strings.HasPrefix(content, "[") {
		content = "[" + content + "]"
	}

	// 处理末尾多余逗号的问题
	content = d.removeTrailingCommas(content)

	return content
}

// removeTrailingCommas 移除JSON中的末尾逗号
func (d *DB) removeTrailingCommas(content string) string {
	// 移除对象末尾的逗号 },}
	content = strings.ReplaceAll(content, ",}", "}")

	// 移除数组末尾的逗号 ,]
	content = strings.ReplaceAll(content, ",]", "]")

	// 处理更复杂的情况：对象间多余的逗号
	lines := strings.Split(content, "\n")
	var result []string

	for i, line := range lines {
		trimmed := strings.TrimSpace(line)

		// 如果当前行是逗号，检查下一行是否是结束符号
		if trimmed == "," {
			// 查看下一个非空行
			nextNonEmptyIdx := i + 1
			for nextNonEmptyIdx < len(lines) && strings.TrimSpace(lines[nextNonEmptyIdx]) == "" {
				nextNonEmptyIdx++
			}

			if nextNonEmptyIdx < len(lines) {
				nextTrimmed := strings.TrimSpace(lines[nextNonEmptyIdx])
				if nextTrimmed == "}" || nextTrimmed == "]" {
					// 跳过这个多余的逗号
					continue
				}
			}
		}

		// 检查行末是否有多余的逗号
		if strings.HasSuffix(trimmed, ",") {
			// 查看下一个非空行
			nextNonEmptyIdx := i + 1
			for nextNonEmptyIdx < len(lines) && strings.TrimSpace(lines[nextNonEmptyIdx]) == "" {
				nextNonEmptyIdx++
			}

			if nextNonEmptyIdx < len(lines) {
				nextTrimmed := strings.TrimSpace(lines[nextNonEmptyIdx])
				if nextTrimmed == "}" || nextTrimmed == "]" {
					// 移除末尾逗号
					line = strings.TrimSuffix(line, ",")
				}
			}
		}

		result = append(result, line)
	}

	return strings.Join(result, "\n")
}
